<?php
namespace Common\Lib\Lakala;

/**
 * 拉卡拉支付类
 *
 */
class Lakala
{
    /**
     * 拉卡拉网关快捷商户号
     */
    private $mid = 'DOPCHN000028';
    //private $mid = 'DOPCHN000128';

    /**
     * RSA加密公钥
     */
    private $public_key = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDPg0O4rPQJL1O+jqJ4rBjFVNRAuDmBSoii9pYfPQBaescCVY0irkWWoLyfTT65TjvnPpOx+IfNzBTlB13qCEFm7algREoeUHjFgFNHiXJ2LK/R0+VWgXe5+EDFfbrFCPnmLKG3OcKDGQszP0VOf6VVTM1t56CpgaRMm1/+Tzd2TQIDAQAB';

    /**
     * 私钥
     */
    private $private_key = 'MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBALHvdfTv+4yorq1lHkB4mF59Akd9QcEl5ZGQTUIEA2/VE8us1dASMCMuGH4t1rRQGTtdv0VpxnXD6PxQur4BSMTcXY4PACAzsZ4trxw6Z/b8PuKEbBad+VwMtbscbcrmieGwrLOUd+iZ3FJmb5SGG5ebImf9EMjB4kote1uBpb+TAgMBAAECgYAQGwimPwKZ3LrS3xA57bB8/Puz1Naa0P9Siak0jIBzIupDyUUhLERHKuj0otmIQKfIA9hIRCa+ihkQnY4JnLwlTnW4BZ7eepdErMUYYwvB4RM5lSj86LrVB9WkpQE/TAjPi60OKjs1sUzjBdjnc8FS8Q8h5JqtCYLuLJmGmSPQAQJBAPYMIvhpSDk+z5DbnBzr6xLr0xToyvrCm1vDNITmRJzx4xC0lk6UVGRaHTmJryACkpyL/JRv2JN1fDOtuQv/HgECQQC5IgMymh6EpOZCo/qr5HGM7GhR4iYariHDTXo4rX0VSMddT44G0n4XXGOqZe0jboYvshWgXII2Xfj6regVkYWTAkAPEO0vQtseTj9NgnULvFJ3pSMWu656LmJu+wQDQ0peRd1+j2BIzYJhZrc1Z73meuHZXiUIPdUIKoCBdZjIKEYBAkAnn9MFYp1DkLPD8ar2XYe8POE7HWdAcKLDVXLibKeIBbK+Ewf4B9d7Eog2cWhnHAHWdYxRbVtlXYmrxcsVyrbHAkBAvDI+ahENs5BfVz/AZ+ItCZ+5BFryG3gFuKaqXMi+MSanPCSDaZbEEcQAh0r4h4MWjBlunj5hcwbIwfY8x2j7';
    //private $private_key = 'MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAJCTrrq0dAMT+xgl5XTnwRezoaWokOwLspFKLDUpNzDctPyEXK/eY9aQ6UYIkPgtKz8PCAr0G7NNdbF4ICG1Fr9uF6PLNI7xn0zQuLGIm3XRNryU9EiZB1mXDC3IIfVzvURAwLFJb74v7/PBsGeDykXF36REBCYXqzM7sLFBNTMLAgMBAAECgYAEyF3nX0DXOTn9OoO0slX46sBWMpVYuapWlBWSTKK+ww5ZrCdEyh6TYofVAUOKcjQUCfNCKYEhFVbnYAnwE4WFEuzCGB75BmPFNNCJuCmy2+rMOeWDCwuxuh1lBmRdCIMqwiAYgbl3rlsMH8//d4sVCeA+woX7wE0Pg1fIQZjBgQJBAMC4OBcUznEAU4tQd0cGEZoi2j8uEFWjbNSognFyJiV0/6yYk+Pk6iojGr9SIAB1NWIRMe/xjc9whrGBZrRXVSkCQQDADKTAR0q7kVLxmYW+0X4AkI+Yo6ENscRl6tsRkDtdX393eu7k1jv0eWz7RNvgjTOzekw3LE3bf6fE1hG1XfkTAkAQoRS98R6rI4MR91yDdWOZcD5yyy+/o/1lEDFJRrdB7imNpBDGzl7iSesp7RUz1OlJUACGGsrIxoXo1SiekRaZAkAl1NfHgMO5+0CpkyKDmmUF23RODz20ouYbZY5OAWmQVTWY5cCVl5Yr7JeJT+E4dNhQbLEC1Vlo+daksb6/SYm9AkBVsPSeSRChkb3mLAV4fsntyotuX/Jvvb5/WTtxqMNm275zueq8z6isUd0bQB9w9YzZk9x4GX4DtuEa/CXpxSg9';


    /**
     * 支付、订单查询地址
     * @var string
     */
    private $ppayGateUrl = 'https://intl.lakala.com:7777/ppayGate/CrossBorderHtml5Pay.do';

    /**
     * 支付/对账回调地址
     * @var string
     */
    private $callback_url = 'http://appapi.lpaiche.com/Recharge/result'; //前台跳转地址,同步显示
    private $notify_url = 'http://appapi.lpaiche.com/Recharge/background'; //后台通知地址,异步
    private $notifyAddrUrl = 'http://appapi.lpaiche.com/Recharge/check_accounts';//对账

    /**
     * 协议版本号
     * @var string
     */
    private $ver = '1.0.0';

    /**
     * 业务类型
     * @var string
     */
    private $reqType = 'B0002';

    /**
     * 跨境业务类型
     * @var string
     */
    private $bizCode = '121010';

    /**
     * 默认时区 GMT+8
     * @var string
     */
    private $timeZone = 'GMT+8';

    /**
     * 订单币种
     * @var string
     */
    private $currency = 'CNY';

    /**
     * 设置业务类型
     */
    public function setReqType($type)
    {
        $this->reqType = $type;
    }

    /**
     * 构建订单数据
     * @param string $orderId 订单ID
     * @param float $orderAmount 订单金额
     * @param string $orderTime 发生时间
     * @param string $orderSummary 订单概要
     * @return array
     */
    public function create_order($orderId, $orderAmount, $orderTime, $orderSummary)
    {
        $mid = $this->mid;
        $public_key = $this->rsa_ges($this->public_key, 'public');
        $private_key = $this->rsa_ges($this->private_key, 'private');
        $ver = $this->ver;
        $reqType = $this->reqType;
        $pageUrl = $this->callback_url;
        $bgUrl = $this->notify_url;
        $ts = date('YmdHis') . mt_rand(100000, 999999);

        $merDesStr = md5($mid);
        $encKeyStr = $ts . $merDesStr;
        $encrypted = $maced = '';
        //公钥加密
        openssl_public_encrypt($encKeyStr, $encrypted, $public_key);
        //密钥密文
        $encKey = strtoupper(bin2hex($encrypted));

        $orderData = array(
            'merOrderId' => $orderId,
            'currency' => $this->currency,
            'ts' => $ts,
            'orderAmount' => $orderAmount,
            'payeeAmount' => $orderAmount,
            'orderTime' => $orderTime,
            'bizCode' => $this->bizCode,
            'orderSummary' => $orderSummary,
            'timeZone' => $this->timeZone,
            'pageUrl' => $pageUrl,
            'bgUrl' => $bgUrl,
        );
        $json_init = $this->json_encode_s($orderData);
        $json = $this->des_encrypt($merDesStr, $json_init);
        $macStr = $mid . $ver . $ts . $reqType . $json;
        $macStr = sha1($macStr);
        openssl_private_encrypt($macStr, $maced, $private_key); //私钥加密
        $mac = strtoupper(bin2hex($maced));

        $result = array(
            'data' => array(
                'ver' => $ver,
                'merId' => $mid,
                'ts' => $ts,
                'pageUrl' => $pageUrl,
                'bgUrl' => $bgUrl,
                'reqType' => $reqType,
                'encKey' => $encKey,
                'encData' => $json,
                'mac' => $mac,
            ),
            'ppayGateUrl' => $this->ppayGateUrl,
        );
        return $result;
    }

    //查询订单
    public function query_order($out_trade_no)
    {
        $mid = $this->mid;
        $ver = $this->ver;
        $reqType = 'B0007';
        $public_key = $this->rsa_ges($this->public_key, 'public');
        $private_key = $this->rsa_ges($this->private_key, 'private');

        $ts = date('YmdHis') . mt_rand(100000, 999999);
        $merDesStr = md5($mid);
        $encKeyStr = $ts . $merDesStr;
        $encrypted = $maced = '';

        //公钥加密
        openssl_public_encrypt($encKeyStr, $encrypted, $public_key);
        //密钥密文
        $encKey = strtoupper(bin2hex($encrypted));

        //业务数据
        $map = array(
            'merOrderId' => $out_trade_no,
        );
        $json = $this->json_encode_s($map);
        //使用对称密钥加密以后的json1
        $json1 = $this->des_encrypt($merDesStr, $json);
        $macStr = $mid.$ver.$ts.$reqType.$json1;
        //商户私钥加密以后的mac
        $macStr = sha1($macStr);
        openssl_private_encrypt($macStr, $maced, $private_key); //私钥加密
        $mac = strtoupper(bin2hex($maced));

        //需要请求的数据
        $http_data = array(
            'ver' => $ver,
            'merId' => $mid,
            'ts' => $ts,
            'reqType' => $reqType,
            'encKey' => $encKey,
            'encData' => $json1,
            'mac' => $mac
        );
        $state = $this->getCurl($this->ppayGateUrl,$http_data,1);
        $result = json_decode($state,true);
        if((json_last_error() == JSON_ERROR_NONE)){
            return $result;
        }
        return false;
    }


    /**
     * 请求接口返回内容
     *
     * @param  string $url [请求的URL地址]
     * @param  string $header [header权限校验参数]
     * @param  json $params [请求的参数]
     * @param  int $ipost [是否采用POST形式]
     * @return  string
     */
    public function getCurl($url, $params='', $ispost=0){
        $httpInfo = array();
        $ch = curl_init();
        $header = array(
            "content-type: application/x-www-form-urlencoded; charset=UTF-8",
        );
        curl_setopt($ch, CURLOPT_HTTP_VERSION , CURL_HTTP_VERSION_1_1 );
        curl_setopt($ch,CURLOPT_USERAGENT,"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)");
        curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT , 30 );
        curl_setopt( $ch, CURLOPT_TIMEOUT , 30);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER , true );
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

        $data = http_build_query($params);
        /*备注： 如果后期需要对http通讯过程中的数据做加密传输，则打开以下代码*/
        // $m = new \Common\Org\Xcrypt($key, 'ecb', 'auto');
        // $data = $m->encrypt($a);
        if( $ispost )
        {
            curl_setopt( $ch , CURLOPT_POST , true );
            curl_setopt( $ch , CURLOPT_POSTFIELDS , $data );
            curl_setopt( $ch , CURLOPT_URL , $url );
        }
        else
        {
            $strUrl = !empty($data) ? $url.'?'.$data : $url;
            curl_setopt( $ch , CURLOPT_URL , $strUrl);
        }
        $response = curl_exec( $ch );
        if ($response === FALSE) {
            return false;//json_encode(array('code'=>"009454",'msg'=>'AN接口访问异常'));
        }
        $httpCode = curl_getinfo( $ch , CURLINFO_HTTP_CODE );
        $httpInfo = array_merge( $httpInfo , curl_getinfo( $ch ) );
        curl_close( $ch );
        return $response;
    }

    //商户退款
    public function refund()
    {

    }

    /**
     * json数据强制转字符串类型
     * @param array $array 待转换的数组
     * @return string 转换后的json字符串
     * @author chunkuan <urcn@qq.com>
     */
    private function json_encode_s($array)
    {
        foreach ($array as &$v) {
            $v = (string)$v;
        }
        return json_encode($array);
    }

    /**
     * RSA 公钥私钥格式化
     * @param string $str 无序公钥、私钥
     * @param string $type public OR private
     * @return string 格式化之后的公钥私钥
     * @author chunkuan <urcn@qq.com>
     */
    public function rsa_ges($str, $type = 'public')
    {
        $publicKeyString = "-----BEGIN " . strtoupper($type) . " KEY-----\n";
        $publicKeyString .= wordwrap($str, 64, "\n", true);
        $publicKeyString .= "\n-----END " . strtoupper($type) . " KEY-----\n";
        return $publicKeyString;
    }

    /**
     * 支付后同步返回验签结果
     * @param array $data 返回的post数组
     * @return array 解密后的支付数据
     * @author chunkuan <urcn@qq.com>
     */
    public function decryptReqData($data)
    {
        $public_key = $this->rsa_ges($this->public_key, 'public');
        $return_data = array('status' => 0, 'data' => array(), 'error' => '');
        $retCode = $data['retCode'];
        $retMsg = $data['retMsg'];
        $merId = $data['merId'];
        $ver = $data['ver'];
        $ts = $data['ts'];
        $reqType = $data['reqType'];
        $reqEncData = $data['encData'];
        $reqMac = $data['mac'];
        $macData = sha1(mb_convert_encoding($retCode . $retMsg . $merId . $ver . $ts . $reqType . $reqEncData, 'gbk', 'utf-8'));
        $reqMacStr = '';
        openssl_public_decrypt(hex2bin(strtolower($reqMac)), $reqMacStr, $public_key);
        if ($macData != $reqMacStr) {
            $return_data['error'] = 'MAC校验失败';
            return $return_data;
        }
        $merKey = md5($merId);
        $reqData = $this->des_decrypt($merKey, $reqEncData);
        if (empty($reqData)) {
            $return_data['error'] = '解密业务参数失败';
            return $return_data;
        }
        $return_data['status'] = 1;
        $return_data['data'] = json_decode($reqData, true);
        return $return_data;
    }

    function decryptAsyncData($data)
    {
        $return_data = array('status' => 0, 'data' => array(), 'error' => '');
        $merPrivateKey = $this->rsa_ges($this->private_key, 'private');
        $platPublicKey = $this->rsa_ges($this->public_key, 'public'); //公钥
        //解密请求数据
        $ts = $data['ts'];
        $reqType = $data['reqType'];
        $reqEncKey = $data['encKey'];
        $reqEncData = $data['encData'];
        $reqMac = $data['mac'];
        //用请求方公钥解签
        $reqmacStr = sha1($ts . $reqType . $reqEncData);
        $myMacStr = '';
        openssl_public_decrypt(hex2bin(strtolower($reqMac)), $myMacStr, $platPublicKey);
        if ($myMacStr != $reqmacStr) {
            echo 'mac校验失败';
            $return_data['error'] = 'MAC校验失败';
            return $return_data;
        }
        $merKey = ""; //商户对称密钥
        openssl_private_decrypt(hex2bin(strtolower($reqEncKey)), $merKey, $merPrivateKey);
        $merKey = substr($merKey, strlen($merKey) - 32, 32);
        $reqData = $this->des_decrypt($merKey, $reqEncData);
        if (empty($reqData)) {
            $return_data['error'] = '解密业务参数失败';
            return $return_data;
        }
        $return_data['status'] = 1;
        $return_data['data'] = json_decode($reqData, true);
        return $return_data;
    }

    /* * **** DES 加密解密库 Start ******** */
    /**
     * des加密用到的临时函数
     */
    private function des_pkcs5_pad($text, $blocksize)
    {
        $pad = $blocksize - (strlen($text) % $blocksize);
        return $text . str_repeat(chr($pad), $pad);
    }

    /**
     * des加密字符串
     * @param string $key 加密密钥
     * @param string $data 待加密字符串
     * @return 加密后的十六进制数据
     * @author chunkuan <urcn@qq.com>
     */
    private function des_encrypt($key, $data)
    {
        $size = mcrypt_get_block_size('des', 'ecb');
        $data = $this->des_pkcs5_pad($data, $size);
        $td = mcrypt_module_open('des', '', 'ecb', '');
        $iv = @mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
        @mcrypt_generic_init($td, $key, $iv);
        $data = mcrypt_generic($td, $data);
        mcrypt_generic_deinit($td);
        mcrypt_module_close($td);
        return strtoupper(bin2hex($data));
    }

    /**
     * 解密用到的临时函数
     */
    private function des_pkcs5_unpad($text)
    {
        $pad = ord($text{strlen($text) - 1});
        if ($pad > strlen($text)) {
            return false;
        }
        if (strspn($text, chr($pad), strlen($text) - $pad) != $pad) {
            return false;
        }
        return substr($text, 0, -1 * $pad);
    }

    /**
     * des解密字符串
     * @param string $key 加密密钥
     * @param string $data 待解密字符串
     * @return 解密后的数据
     * @author chunkuan <urcn@qq.com>
     */
    public function des_decrypt($key, $data)
    {
        $data = hex2bin(strtolower($data));
        $td = mcrypt_module_open('des', '', 'ecb', '');
        $iv = @mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
        $ks = mcrypt_enc_get_key_size($td);
        @mcrypt_generic_init($td, $key, $iv);
        $decrypted = mdecrypt_generic($td, $data);
        mcrypt_generic_deinit($td);
        mcrypt_module_close($td);
        $result = $this->des_pkcs5_unpad($decrypted);
        return $result;
    }

    /* * **** DES 加密解密库 End ******** */

}